/*
   ============================================================================
   Programmname: logik_checkers.c
   Autor       : Sebastian Spiller
                 HHBK Gruppe A
   Datum       : 07.05.2011
   Projekt     : C-Spiele
   Version     : 1.0
   Aenderung   : -

   Programmschnittstelle: int main(void)
                          Das Programm gibt den Wert 0 oder 1 zurueck.
                          Es werden keine Argumente erwartet.

   Hier wird die Spiellogik von Checkers (Dame) implementiert.

   ============================================================================
*/


/*
============================================================================
Präprozessoranweisungen
============================================================================
*/
#include "util.h"


/**
 * Erzeugt Brett und Eingabe
 * @param  void
 * @return int 0 / 1, 0 fuer korrekten Ablauf
 */
int renderCheckers(void)
{
    int aiMove[2][2];

    int iPlayer     = 1;
    int iNextPlayer = 0;
    int iIsWon      = FALSE;
    int iErrorFlag  = FALSE;
    int iFirstRound = TRUE;

    initCheckers();

    aiMove[START][ROW]  = 0;
    aiMove[START][COL]  = 0;
    aiMove[TARGET][ROW] = 0;
    aiMove[TARGET][COL] = 0;

    do
    {
        clrscr();

        if (FALSE == iFirstRound)
        {
            printf("\nZugkoordinaten:");
            printf("%c%c",  65 + aiMove[START][COL], 49 + aiMove[START][ROW]);
            printf(" - %c%c\n", 65 + aiMove[TARGET][COL], 49 + aiMove[TARGET][ROW]);
        } // if
        else
        {
            printf("Welcome 2 Checkers\n\n");
            iFirstRound = FALSE;
        } // else

        if ( TRUE == iErrorFlag)
        {
            printf("Fehler: %s", acErrorMsg);
            printf("Spieler %i, ziehe erneut\n\n", iPlayer);
            iErrorFlag = FALSE;
        } // if
        else
        {
            if ('\0' != acEvent[0])
                printf("Ereignis: %s",acEvent);
            
            printf("Spieler %i an der Reihe\n\n", iPlayer);
        } // else

        strcpy(acErrorMsg, "");
        strcpy(acEvent, "");
        printBoard();

        // Fehler-Validierung mit Zugeingabe in getMove
        if (TRUE == getMove(aiMove))
        {
            // Zug des Spielers mit Fehlerausgabe ueber Global acErrorMsg
            if ( FALSE != checkMove(aiMove, iPlayer, TRUE) )
            {

// @todo: zugzwang auch wenn dame erhalten
// @todo: zugkoordinaten D8 - D8
                // Herrscht Zugzwang?
                if (  (2 == checkGameStatus(iPlayer))
                    && (  (-2 != (aiMove[TARGET][ROW] - aiMove[START][ROW]))
                       && ( (aiMove[TARGET][ROW] - aiMove[START][ROW]) != 2 )  )   )
                {
                } // if
                else
                {
                    moveToken(aiMove, iPlayer);

                    aiMove[START][ROW] = aiMove [TARGET][ROW];
                    aiMove[START][COL] = aiMove [TARGET][COL];

                    // Hat naechster Spieler noch Zugmoeglichkeiten?
                    iNextPlayer = changePlayer(iPlayer);

                    if ( TRUE == checkGameStatus(iNextPlayer) )
                        iIsWon = TRUE;
// @todo: man ist nur mit einer figur im zugzwang pro runde
                    // Zugzwang naechste Runde? Dann kein Spielerwechsel
                    else if (TRUE == checkMoveQueue(aiMove, iPlayer))
                    {
                    } // else if

                    else
                        iPlayer = changePlayer(iPlayer);

                } // else
            } // if
            else
                iErrorFlag = TRUE;
        } // if
        else
            iErrorFlag = TRUE;
    }
    while (FALSE == iIsWon);

    clrscr();

    printf("\n\nGewinner ist Spieler %i\n\n", iPlayer);
    printBoard();

    getchar();

    return 0;
} // function




/**
* Ueberprueft ob noch ein weiterer einfacher Zug moeglich ist
* @param  int aiMove[2][2] Token-Koordinaten [Row, Column]
* @param  int iPlayer   SpielerID des Spielers, der dran ist
* @return int TRUE / FALSE  Gibt an, ob noch ein Zug moeglich ist
*/
int checkMovePossible(int aiMove[2][2], int iPlayer)
{
 // prueft nicht die richtung, uebernimmt checkMove dafuer
    int iReturn      = FALSE;
    int iCounter     = 0;

    // Ist der Stein vom Spieler, der am Zug ist?
    if ( TRUE == checkIsTokenFromPlayer(aiMove, iPlayer) )
    {
        for (iCounter = -1; ( (iCounter <= 1) && (iReturn != TRUE) ); iCounter++)
        {
            aiMove[TARGET][ROW] = aiMove[START][ROW] + iCounter;
            aiMove[TARGET][COL] = aiMove[START][COL] + iCounter;

            // Ist noch ein Zug moeglich? Bedingung funktioniert als Flag
            if ( TRUE == checkMove(aiMove, iPlayer, FALSE) )
                iReturn = TRUE;
        } // for
    } // if
    
    return iReturn;

} // function

/**
* Ueberprueft ob noch ein weiterer Zug moeglich ist
* @param  int aiStart[2][2] Token-Koordinaten [Row, Column]
* @param  int iPlayer   SpielerID des Spielers, der dran ist
* @return int TRUE / FALSE  Gibt an, ob noch ein Zug moeglich ist
*/
int checkIsTokenFromPlayer(int aiStart[2][2], int iPlayer)
{
    int iReturn = 0;

    switch (aiBoard[aiStart[START][ROW]][aiStart[START][TARGET]])
    {
        case 1:
        case 3:
            iReturn = ((iPlayer == 1) ? TRUE : FALSE );
            break;

        case 2:
        case 4:
            iReturn = ((iPlayer == 2) ? TRUE : FALSE );
            break;

        default:
            iReturn = FALSE;
    } // switch

    return iReturn;

} // function



/**
* Ueberprueft, ob das Spiel von einem der beiden Spieler gewonnen wurde.
* @param  int iPlayer SpielerID des Spielers, der am Zug ist
* @return int         0: noch kein Spieler hat gewonnen ,
*                     1: Es gibt einen Gewinner
*/
int checkGameStatus(int iPlayer)
{
    int iReturn       = TRUE;
    int iRow          = 0;
    int iCol          = 0;
    int aiStart[2][2];

    for (iRow = 0; iRow <= NO_OF_ROWS; iRow++)
    {
        for (iCol = 0; (iCol <= NO_OF_COLS); iCol++)
        {
            // Liegt ein Stein auf dem Feld?
            if (0 != aiBoard[iRow][iCol])
            {

                // @todo: hier auch
                aiStart[START][ROW] = iRow;
                aiStart[START][COL] = iCol;

                // Spielzugzwang noetig?
                if (TRUE == checkMoveQueue(aiStart, iPlayer))
                    iReturn = 2;

                // Spielzug moeglich?
                if ( (2 != iReturn) && (TRUE == checkMovePossible(aiStart, iPlayer)) )
                    iReturn = FALSE;
            } // if
        } // for
    } // for

    return iReturn;
} // function


/**
 * Ueberprueft ob der Zugfolge eingetreten
 * @param  int aiStart[2][2] Zug mit Start und Zielkoordinaten [Start/Ziel][Row/Column]
 * @param  int iPlayer      Spieler, der am Zug ist
 * @return int TRUE / FALSE Ist Zug moeglich?
 */
int checkMoveQueue(int aiStart[2][2], int iPlayer)
{
    int i = 0;
    int j = 0;
    int iReturn = FALSE;
    int aiAroundStart[2][2];

    if (FALSE == checkIsTokenFromPlayer(aiStart, iPlayer))
        return FALSE;

    // Verpflichtetes Schlagen
// @todo: anpassen fuer checkMove!!!
    if (1 == iPlayer)
        i = 1;

    else if (2 == iPlayer)
        i = -1;

    // Ist Figur Dame?
    else if ( 2 < aiBoard[aiStart[START][ROW]][aiStart[START][COL]])
    {
        i = -1;
        for (j = -1; j <= 1; j += 2)
        {
            aiAroundStart[START][ROW] = aiStart[START][ROW] + i;
            aiAroundStart[START][COL] = aiStart[START][COL] + j;

            if (0 !=  aiBoard[aiAroundStart[START][ROW]][aiAroundStart[START][COL]])
            {
                if (FALSE == checkIsTokenFromPlayer(aiAroundStart, iPlayer))
                {
                    if ( 0 == (aiBoard[aiStart[START][ROW] + 2 * i][aiStart[START][COL] + 2 * j]) )
                        iReturn = TRUE;
                } // if
            } // if
        } // for
        i = 1;
    } // else if

    if (0 != i)
    {
        for (j = -1; j <= 1; j += 2)
        {
            aiAroundStart[START][ROW] = aiStart[START][ROW] + i;
            aiAroundStart[START][COL] = aiStart[START][COL] + j;

            if (0 != aiBoard[aiAroundStart[START][ROW]][aiAroundStart[START][COL]])
            {
                if (FALSE == checkIsTokenFromPlayer(aiAroundStart, iPlayer))
                {
                    if ( 0 == (aiBoard[aiStart[START][ROW] + 2 * i][aiStart[START][COL] + 2 * j]) )
                        iReturn = TRUE;
                } // if
            } // if
        } // for
    } // if
    
    i = 0;
    
    return iReturn;
} // function



/**
 * Figur schlagen
 * @param  int aiMove[2][2] Zug mit Start und Zielkoordinaten [Start/Ziel][Row/Column]
 * @param  int iPlayer Spieler an der Reihe
 * @return int TRUE / FALSE Ist Zug moeglich?
 */
int kickToken(int aiMove[2][2], int iPlayer)
{
    int iReturn = FALSE;
    int iEnemyRow = 0;
    int iEnemyCol = 0;

    if (     (  ( 2  == (aiMove[TARGET][ROW] - aiMove[START][ROW]) )
            ||( (-2) == (aiMove[TARGET][ROW] - aiMove[START][ROW]) )  )   )
    {
        if( 0 < (aiMove[TARGET][ROW] - aiMove[START][ROW]) )
            iEnemyRow = aiMove[START][ROW] + 1;
        else
            iEnemyRow = aiMove[START][ROW] -1;

        if( 0 < (aiMove[TARGET][COL] - aiMove[START][COL]) )
            iEnemyCol = aiMove[START][COL] + 1;
        else
            iEnemyCol = aiMove[START][COL] -1;

        aiBoard[iEnemyRow][iEnemyCol] = 0;
        iReturn = TRUE;

    } // if
    return iReturn;
} // function



/**
 * Ueberprueft ob der Zug legal ist
 * @param  void
 * @param  int aiMove[2][2] Zug mit Start und Zielkoordinaten [Start/Ziel][Row/Column]
 * @param  int iPlayer      Spieler, der am Zug ist
 * @param  int iShowErrors  Wenn Computer an der Reihe ist, keine Errors senden
 * @return int TRUE / FALSE Ist Zug moeglich?
 */
int checkMove(int aiMove[2][2], int iPlayer, int iShowErrors)
{
    int iCheck   = TRUE;
    int iStart   = 0;
    int iTarget  = 0;
    int iMoveCol = 0; // Differenz aus Start- und Endkoordinaten in Spaltenrichtung
    int iMoveRow = 0; // analog

    char acErrorCache[1024] = {'\0'};
    char acEventCache[1024] = {'\0'};

    int iTargetRow = aiMove[TARGET][ROW];
    int iTargetCol = aiMove[TARGET][COL];

    iStart  = aiBoard[aiMove[START][ROW]][aiMove[START][COL]];
    iTarget = aiBoard[iTargetRow][iTargetCol];

    iMoveCol = aiMove[TARGET][COL] - aiMove[START][COL];
    iMoveRow = aiMove[TARGET][ROW] - aiMove[START][ROW];


    // Eingabefeld == Ausgabefeld
    if (  ( aiMove[START][ROW] ==  aiMove[TARGET][ROW])
       && ( aiMove[START][COL] ==  aiMove[TARGET][COL]) )
    {
        iCheck = FALSE;
        strcat(acErrorCache, "Startfeld und Zielfeld identisch\n");
    } // if


    // Startfeld leer
    if ( 0 == aiBoard[aiMove[START][ROW]][aiMove[START][COL]] )
    {
        iCheck = FALSE;
        strcat(acErrorCache, "Startfeld ist leer\n");
    } // if

// @todo: Ausgabe erfolgt zwei mal
    // ZielFeld besetzt
    if ( 0 != aiBoard[aiMove[TARGET][ROW]][aiMove[TARGET][COL]] )
    {
        iCheck = FALSE;
        strcat(acErrorCache, "Zielfeld ist besetzt\n");
    } // if


    // Figur nicht vom Spieler
    if ( FALSE == checkIsTokenFromPlayer(aiMove, iPlayer) )
    {
        iCheck = FALSE;
        strcat(acErrorCache, "Spielfigur ist vom Gegner\n");
    } // if


    // Zug nicht diagonal
    if ( ( iMoveCol != iMoveRow ) && ((iMoveCol * (-1)) != iMoveRow) )
    {
        iCheck = FALSE;
        strcat(acErrorCache, "Spielzug ist nicht diagonal\n");
    } // if


    // Sprungweite zu gross
    if (    (  2 < (aiMove[TARGET][ROW] - aiMove[START][ROW]) )
          ||( -2 > (aiMove[TARGET][ROW] - aiMove[START][ROW]) )  )
    {
        iCheck = FALSE;
        strcat(acErrorCache, "Sprung zu weit\n");
    } // if


   // Handelt es sich nicht um eine Dame?
    if ( 3 > iStart)
    {
        // Zugrichtung korrekt?
        if ( (1 == iPlayer) && (aiMove[TARGET][ROW] < aiMove[START][ROW]) )
        {
            iCheck = FALSE;
            strcat(acErrorCache, "Zugrichtung fuer einfache Spielfigur nur nach oben \n");
        } // if
        
        // Zugrichtung korrekt?
        if ( (2 == iPlayer) && (aiMove[TARGET][ROW] > aiMove[START][ROW])  )
        {
            iCheck = FALSE;
            strcat(acErrorCache, "Zugrichtung fuer einfache Spielfigur nur nach unten \n");
        } // else if
    } // if

// @todo: Prooch: Stein nicht schlagen beim Spielfeld-Check
    if ( (TRUE == iCheck ) && (TRUE == iShowErrors ) && (TRUE == checkMoveQueue(aiMove, iPlayer)) )
    {
        // Checked ob Kicken erlaubt ist // IPLAYER
        if ( FALSE == kickToken(aiMove, iPlayer) )
            strcat(acEventCache, "Du musst schlagen!\n");
        else
        {
            // @todo: Prooch fuer Stein geschlagen zurueckgeben sonst glob var?!
            iCheck = 2;
            strcat(acEventCache, "Gegnerischen Stein geschlagen!\n");
        } // else
    } // if


    // Fehler an Fehlerausgabe weiterleiten
    if (TRUE == iShowErrors)
    {
        strcat(acErrorMsg, acErrorCache);
        strcat(acEvent, acEventCache);
    } // if

    /* Cache leeren */
    acErrorCache[0] = '\0';
    acEventCache[0] = '\0';
    
    return iCheck;
} // function



/**
* Initialisiere Spielbrett-Array mit Figurenpositionen
* @param  void
* @return TRUE / FALSE    Eingabe erfolgreich
*/
int initCheckers(void)
{
    int iRow      = 0;
    int iCol      = 0;

    return TRUE;

    for (iRow = 0; iRow < NO_OF_ROWS; iRow++)
    {
        for (iCol = 0; iCol < NO_OF_COLS; iCol++)
        {
            aiBoard[iRow][iCol] = 0;

            if ((iRow < 3) && (0 == ((iRow + iCol) % 2)))
                aiBoard[iRow][iCol] = 1;
            else if ( (iRow > 4) && (0 == ((iRow + iCol) % 2)) )
                aiBoard[iRow][iCol] = 2;
        } // for
    } // for

    return TRUE;
} // function



/**
* Fuehre Spielzug aus
* @param void
* @param int aiMove[2][2] SpielZug
*/
void moveToken(int aiMove[2][2], int iPlayer)
{
    int iToken = 0;

    iToken = aiBoard[aiMove[START][ROW]][aiMove[START][COL]];
    aiBoard[aiMove[START][ROW]][aiMove[START][COL]] = 0;
    aiBoard[aiMove[TARGET][ROW]][aiMove[TARGET][COL]] = iToken;

    // mache Figur zur Dame, nur wenn natuerlich einfache Figur
    if (
           ( (7 == aiMove[TARGET][ROW]) && (1 == iPlayer) && (2 >= iToken) )
        || ( (0 == aiMove[TARGET][ROW]) && (2 == iPlayer) && (2 >= iToken) )
       )
    {
        aiBoard[aiMove[TARGET][ROW]][aiMove[TARGET][COL]] +=2;
        if (1 == iPlayer)
            strcat(acEvent,"Spieler 1 hat eine Dame bekommen.\n");
        else
            strcat(acEvent,"Spieler 2 hat eine Dame bekommen.\n");
    } // if
    
} // function

/**
* Kontrolliert den Spielerwechsel (flipflop zwischen 1 und 2)
* @param  int iPlayer ID des aktuellen Spielers
* @return int         ID des folgenden Spielers
*/
int changePlayer(int iPlayer)
{
    return (iPlayer == 1) ? 2 : 1;
} // function